﻿// ———————————————————————–
// <copyright file="DataService.svc.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// DataService.svc.cs - "Description"
// Project: "ICNETSOA"- "ICNETRest"
//
// Language:    C#, .NET 4.0
// Platform:    Windows 7, VS 2010
// Author:      Don McGarry The MITRE Corporation
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)
                
using System;
using System.Collections.Generic;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml.Xsl;
using ICNETDAL;
using System.Drawing;
using System.Net;
using EDXLHistory;
using EDXLSharp.EDXLDELib;

namespace ICNETREST
{
  /// <summary>
  /// Methods for pulling information from the database, as well as converting it to HTML.
  /// </summary>
    [ServiceContract(Namespace = "urn:icnet:mitre:org:DataService")]

    // [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class DataService
    {  
      /// <summary>
      /// Map from xml message types to xsl files that can turn them into HTML reports
      /// </summary>
      private static Dictionary<string, string> xmlTransformers = new Dictionary<string, string>() 
        { 
            { "{http://icnet.mitre.org/mEXL/SitRep/}SitRep", "XSLT\\HTML SitRep Legacy.xsl" }, // Minimally tested
            { "{urn:oasis:names:tc:emergency:EDXL:SitRep:1.0}SitRep", "XSLT\\HTML SitRep.xsl" }, // Minimally tested
            { "{urn:oasis:names:tc:emergency:EDXL:RM:1.0:msg}OfferUnsolicitedResource", "XSLT\\HTML RM.xsl" },  // NOT TESTED
            { "{urn:oasis:names:tc:emergency:EDXL:HAVE:1.0}HospitalStatus", "XSLT\\HTML HAVE.xsl" }, // well Tested
            { "{urn:cot:mitre:org}event", "/XSLT/HTML CoT.xsl" }, // tested, has issues inserting the human readable type string
            { "{urn:oasis:names:tc:emergency:cap:1.1}alert", "XSLT\\HTML CAP 1.1.xsl" },  // NOT TESTED
            { "{urn:oasis:names:tc:emergency:cap:1.2}alert", "XSLT\\HTML CAP 1.2.xsl" }  // NOT TESTED
        };
        
      private static Dictionary<string, string> xmlDashboardTransformers = new Dictionary<string, string>() 
        { 
            { "ManagementReportingSummary", "MRS.xslt" }, 
            { "SituationInformation", "SI.xslt" }, 
            { "CasualtyAndIllnessSummary", "CIS.xslt" },  
            { "ResponseResourcesTotals", "RRT.xslt" }, 
        };

        /// <summary>
        ///  Used for padding short error messages, which are not shown in some browsers if the message is under 512 bytes.
        /// </summary>
        private string lorem = "<!-- " + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pellentesque rutrum tincidunt. " +
                                        "Proin mauris ante, dignissim id elementum a, malesuada vel purus. Pellentesque est mi, sollicitudin " +
                                        "nec semper convallis, luctus ut tortor. Sed nec quam turpis. In hac habitasse platea dictumst. Proin " +
                                        " luctus turpis vel metus lobortis a eleifend neque rhoncus. Nam non laoreet libero. Sed cursus tincidunt" +
                                        " dui non vehicula. Nam sagittis ante nec magna feugiat facilisis. Etiam odio sem, vestibulum sed sed. " + " -->";

      /// <summary>
      /// The header of the HTTP message.
      /// </summary>
        private string httpHeaders = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                     "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> ";

      /// <summary>
      /// Pulls the DE content out the database by referencing its hash value. 
      /// </summary>
      /// <param name="contentKeyStr">The hash value of the object. </param>
      /// <returns>The DE object</returns>
        [WebGet(UriTemplate = "XML/{ContentKeyStr}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public XElement GetXML(string contentKeyStr)
        {
          int hash;
          bool canParse = Int32.TryParse(contentKeyStr, out hash);

          if (!canParse)
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return null;
          }
          else
          {
            EDXLDEDal dal = new EDXLDEDal();
            XElement xe = dal.GetContentObjectByHash(hash);
            return xe;
          }
        }

        /// <summary>
        /// Pulls the DE out the database by referencing DE Id and Sender 
        /// </summary>
        /// <param name="contentKeyStr">The hash value of the object. </param>
        /// <returns>The DE object</returns>
        [WebGet(UriTemplate = "DEXML?Id={IdStr}&Sender={Sender}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public XElement GetDEXML(string IdStr, string Sender)
        {

          if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender))
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            WebOperationContext.Current.OutgoingResponse.StatusDescription = "Either Distribution ID or Sender were NULL or Empty.";
            return null;
          }
          else
          {
            EDXLDEDal dal = new EDXLDEDal();
            XElement xe = dal.GetDE(IdStr, Sender);
            return xe;
          }
        }

        /// <summary>
        /// Transform the DE XML into HTML
        /// </summary>
        /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
        /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
        [WebGet(UriTemplate = "DEHTML?Id={IdStr}&Sender={Sender}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public Stream GetDEHTML(string IdStr, string Sender)
        {
          WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
          System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

          if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender))
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected the Distribution Id and Sender at the end of the url.</BODY></HTML>" + this.lorem)) as Stream;
          }
          else
          {
            EDXLDEDal dal = new EDXLDEDal();
            XElement xe = dal.GetDE(IdStr, Sender);
            string DEXSLT = "XSLT\\HTML DE.xsl";

            try
            {
              //return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY> work in progress </BODY></HTML>" + this.lorem)) as Stream;
              return TransformDEXMLtoHTML(xe, DEXSLT);
            }
            catch (System.Exception e)
            {
              WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
              return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Failed to convert to html \"\"  : " + e.Message + "   ----    " +
                  e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</BODY></HTML>" + this.lorem)) as Stream;
            }
          }
        }

        /// <summary>
        /// Transform the DE XML into HTML
        /// </summary>
        /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
        /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
        [WebGet(UriTemplate = "History/DEHTML?Id={IdStr}&Sender={Sender}&DateTime={DateTimeSent}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public Stream GetHistoryDEHTML(string IdStr, string Sender, string DateTimeSent)
        {
          WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
          System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

          if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender) || string.IsNullOrWhiteSpace(DateTimeSent))
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a Distribution Id, Sender, and DateTime at the end of the url.</BODY></HTML>" + this.lorem)) as Stream;
          }
          else
          {
            List<XElement> xeList = History.GetDE(IdStr, Sender, DateTimeSent);
            string DEXSLT = "XSLT\\HTML DE.xsl";

            try
            {
              if (xeList == null || xeList.Count == 0)
              {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
              }
              else
              {
                //return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY> work in progress </BODY></HTML>" + this.lorem)) as Stream;
                return TransformDEXMLtoHTML(xeList[0], DEXSLT);
              }
            }
            catch (System.Exception e)
            {
              WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
              return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Failed to convert to html \"\"  : " + e.Message + "   ----    " +
                  e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</BODY></HTML>" + this.lorem)) as Stream;
            }
          }
        }

        /// <summary>
        /// Parses a URL to find the DE message that it is attempting to look up. 
        /// </summary>
        /// <param name="contentKeyStr">The key on the end of the URL that is used to locate the content</param>
        /// <returns>If the DE message is found, it is returned as XML. If it is not found, or has no content, null is returned. </returns>
        [WebGet(UriTemplate = "History/MIME?Id={IdStr}&Sender={Sender}&DateTime={DateTimeSent}&ContentDescription={ContentDescription}"), OperationContract]
        public Stream GetHistoryMIME(string IdStr, string Sender, string DateTimeSent, string ContentDescription)
        {
          System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

          if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender) || string.IsNullOrWhiteSpace(DateTimeSent) || string.IsNullOrWhiteSpace(ContentDescription))
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a Distribution Id, Sender, DateTime, and ContentDescription at the end of the url.</BODY></HTML>" + this.lorem)) as Stream;
          }
          else
          {
            List<XElement> xeList = History.GetDE(IdStr, Sender, DateTimeSent);

            if (xeList == null || xeList.Count == 0)
            {
              WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
              return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
            }
            else
            {
              EDXLDE de = new EDXLDE(xeList[0].ToString());

              NonXMLContentType nco = GetNonXMLContentObjectByDescription(de, ContentDescription);

              // if we didn't find the content
              if (nco == null)
              {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
              }
              else
              {
                byte[] content = Convert.FromBase64String(nco.ContentData);

                if (content == null || content.Length < 1)
                {
                  WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                  return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
                }
                else
                {
                  MemoryStream ms = new MemoryStream(content);
                  string contentType = nco.MIMEType;

                  if (String.IsNullOrWhiteSpace(contentType))
                  {
                    contentType = "image/jpeg";
                  }

                  WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
                  return ms as Stream;
                }
              }
            }
          }
        }

        private NonXMLContentType GetNonXMLContentObjectByDescription(EDXLDE de, string ContentDescription)
        {
          NonXMLContentType nco = null;

          foreach (ContentObject co in de.ContentObjects)
          {
            if (co.ContentDescription.Equals(ContentDescription))
            {
              nco = co.NonXMLContent;
            }
          }

          return nco;
        }

      /// <summary>
      /// Not used anymore
      /// </summary>
      /// <param name="contentType">Some Filler</param>
      /// <param name="contentKeyStr">More filler</param>
      /// <returns>Even more filler </returns>
      //// Can this be removed now? No longer used, except maybe by automated testing --rgustafson
        [WebGet(UriTemplate = "{ContentType}/{ContentKeyStr}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public XElement Create(string contentType, string contentKeyStr)
        {
          if (contentType.Equals("Test", StringComparison.CurrentCultureIgnoreCase) && contentKeyStr.Equals("Test", StringComparison.CurrentCultureIgnoreCase))
          {
              return new XElement("OK");
          }
          else
          {
            int hash;
            bool canParse = Int32.TryParse(contentKeyStr, out hash);

            if (!canParse)
            {
              WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
              return null;
            }
            else
            {
              EDXLDEDal dal = new EDXLDEDal();
              XElement xe = dal.GetContentObjectByHash(hash);
              return xe;
            }
          }
        }

        // Dummy callback used by 'GetThumbnail' below.
        private bool ThumbnailCallback()
        {
            return false;
        }

        /// <summary>
        /// Returns a thumbnail for a given ContentKeyStr. (In the future it should generates it if needed, otherwise returns a cached copy from the filesystem)
        /// </summary>
        /// <param name="contentKeyStr">The key on the end of the URL that is used to locate the content</param>
        /// <returns>A stream of bytes that is a jpg image </returns>
        [WebGet(UriTemplate = "Thumbnail/{ContentKeyStr}?height={thumbnailHeightStr}"), OperationContract]
        public Stream GetThumbnail(string contentKeyStr, string thumbnailHeightStr)
        {
            int hash;
            int thumbnailHeight;
            bool canParseKey = Int32.TryParse(contentKeyStr, out hash);
            bool canParseHeight = Int32.TryParse(thumbnailHeightStr, out thumbnailHeight);

            if (!(canParseKey&&canParseHeight))
            {
                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Bad params</BODY></HTML>" + this.lorem)) as Stream;
            }
            else
            {
                EDXLDEDal dal = new EDXLDEDal();
                byte[] content = dal.GetNonXMLContentObjectByHash(hash);

                // if we didn't find the content
                if (content == null || content.Length < 1)
                {
                    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                    WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                    return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</BODY></HTML>" + this.lorem)) as Stream;
                }
                else
                {
                    //MemoryStream ms = new MemoryStream(content);
                    string contentType = dal.GetNonXMLMIMETypeByHash(hash);
                    if (!contentType.Contains("image"))
                    {
                        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                        return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") does not link to an image, so no thumbnail is available</BODY></HTML>" + this.lorem)) as Stream;
                    }


                    // Convert byte[] to Image
                    MemoryStream readerStream = new MemoryStream();
                    readerStream.Write(content, 0, content.Length);
                    Image image = Image.FromStream(readerStream, true);
                    


                    MemoryStream outputStream = new MemoryStream();
                    Image.GetThumbnailImageAbort thumbnailCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
                    int thumbnailWidth = (int)( (double)image.Width*((double)thumbnailHeight/(double)image.Height) );
                    Image thumbnail = image.GetThumbnailImage(thumbnailWidth, thumbnailHeight, thumbnailCallback, IntPtr.Zero);

                    thumbnail.Save(outputStream, System.Drawing.Imaging.ImageFormat.Jpeg);

                    outputStream.Position = 0; 
                    WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
                    return outputStream as Stream;
                }
            }
        }



      /// <summary>
      /// Parses a URL to find the DE message that it is attempting to look up. 
      /// </summary>
      /// <param name="contentKeyStr">The key on the end of the URL that is used to locate the content</param>
      /// <returns>If the DE message is found, it is returned as XML. If it is not found, or has no content, null is returned. </returns>
        [WebGet(UriTemplate = "MIME/{ContentKeyStr}"), OperationContract]
        public Stream GetMIME(string contentKeyStr)
        {
          int hash;
          bool canParse = Int32.TryParse(contentKeyStr, out hash);

          if (!canParse)
          {
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a 32 bit signed integer at the end of the url. You provided (" + contentKeyStr + "), which is not parsable as an integer.</BODY></HTML>" + this.lorem)) as Stream;
          }
          else
          {
            EDXLDEDal dal = new EDXLDEDal();
            byte[] content = dal.GetNonXMLContentObjectByHash(hash);

            // if we didn't find the content
            if (content == null || content.Length < 1)
            {
              System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
              WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
              return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</BODY></HTML>" + this.lorem)) as Stream;
            }
            else
            {
              MemoryStream ms = new MemoryStream(content);
              string contentType = dal.GetNonXMLMIMETypeByHash(hash);
              if (String.IsNullOrWhiteSpace(contentType))
              {
                contentType = "image/jpeg";
              }

              WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
              return ms as Stream;
            }
          }
        }

      /// <summary>
      /// Parses a URL to find the DE content that it is attempting to look up. 
      /// </summary>
      /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
      /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
        [WebGet(UriTemplate = "HTML/{ContentKeyStr}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public Stream GetHTML(string contentKeyStr)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
            int hash;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            try
            {
                hash = Int32.Parse(contentKeyStr);
            }
            catch (System.FormatException)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a 32 bit signed integer at the end of the url. You provided (" + contentKeyStr + "), which is not parsable as an integer.</BODY></HTML>" + this.lorem)) as Stream;   
            }

            EDXLDEDal dal = new EDXLDEDal();
            XElement xe = dal.GetContentObjectByHash(hash);

            if (xe == null)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;

                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</BODY></HTML>" + this.lorem)) as Stream;
            }

            string type = xe.Name.ToString();

            // Enable to just echo the type string as HTML
            //// return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY>" + type + "  valid:" + xmlTransformers.ContainsKey(type).ToString() + "</BODY></HTML>" + lorem)) as Stream;

            if (xmlTransformers.ContainsKey(type))
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
                try
                {
                    // return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY>" + HttpRuntime.AppDomainAppPath + xmlTransformers[type] + "</BODY></HTML>" + lorem)) as Stream;
                    return TransformXMLtoHTML(xe, xmlTransformers[type]);
                }
                catch (System.Exception e)
                {
                    WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                    return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Failed to convert to html \"" + type + "\"  : " + e.Message + "   ----    " +
                        e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</BODY></HTML>" + this.lorem)) as Stream;
                }
            }
            else
            {
                // Not able to do transformation to HTML for this message type, fallback to showing the XML
                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;

                return new MemoryStream(encoding.GetBytes(xe.ToString())) as Stream;
            }
        }




        /// <summary>
        /// I Parses a URL to find the DE message that it is attempting to look up. 
        /// </summary>
        /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
        /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
        [WebGet(UriTemplate = "DashboardHTMLAuto/{ContentKeyStr}?release={release}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public Stream GetDashboardHTMLAuto(string contentKeyStr, string release)
        {
            string xsltLocation = "XSLT\\DashboardXSLT\\" + release + "\\";
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
            int hash;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();


            try
            {
                hash = Int32.Parse(contentKeyStr);
            }
            catch (System.FormatException)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>Expected a 32 bit signed integer at the end of the url. You provided (" + contentKeyStr + "), which is not parsable as an integer.</p>" + this.lorem)) as Stream;
            }

            EDXLDEDal dal = new EDXLDEDal();

            //string sitrepSampleType="SituationInformation";

            //XElement xe = dal.GetContentObjectByHash(hash);
            Uri current = new Uri(HttpRuntime.AppDomainAppPath);
            //Uri current = new Uri(@"C:\Users\rgustafson\Documents\IC.NET-newDB\IC.NET-unstable\IC.NETSOA\ICNETREST\");
            XElement xe = dal.GetContentObjectByHash(hash);
            /*
            try
            {
                xe = XElement.Load(new Uri(current, @".\XSLT\DashboardSamples\" + sitrepSampleType + @"\" + hash + @".xml").ToString());
            }
            catch (System.IO.IOException)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>no sample data for those settings</p>" + this.lorem)) as Stream;
            }
             * */

            if (xe == null)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</p>" + this.lorem)) as Stream;
            }
            /*
          else
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>ready "+xe.NodeType.ToString()+"</p>" + this.lorem)) as Stream;
          }*/

            string sitrepType = getDashboardXSLTFilename(xe);
            if (sitrepType == null)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p><pre>Failed to convert to html: \"" + xe.Name.ToString()  + "</pre></p>" + this.lorem)) as Stream; 
            }

            // Enable to just echo the type string as HTML
            //// return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY>" + type + "  valid:" + xmlTransformers.ContainsKey(type).ToString() + "</BODY></HTML>" + lorem)) as Stream;

            //if (xmlDashboardTransformers.ContainsKey(sitrepType))
            //{
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
                try
                {
                    string xsltFullPath = xsltLocation + sitrepType;
                    return TransformXMLtoHTML(xe, xsltFullPath);
                }
                catch (System.Exception e)
                {
                    WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                    return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p><pre>Failed to convert to html \"" + sitrepType + "\"  : " + e.Message + "   ----    " +
                        e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</pre></p>" + this.lorem)) as Stream;
                }
           // }

        /*
            else
            {
                // Not able to do transformation to HTML for this message type, fallback to showing the XML
                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;

                return new MemoryStream(encoding.GetBytes(xe.ToString())) as Stream;
            }
         * */
        }


        private string getDashboardXSLTFilename(XElement xe)
        {
            
            if (xe.Name.LocalName == "SitRep")
                return getSitrepType(xe);
            else
                return null;
            
        }

        private string getSitrepType(XElement xe)
        {
           
            //Get the report element
            XElement report = xe.Element("{urn:oasis:names:tc:emergency:EDXL:SitRep:1.0}Report");
            if (report == null)
            {
                return null;
            }

            //Get the report type attribute
            XAttribute reportTypeAttribute = report.Attribute("{http://www.w3.org/2001/XMLSchema-instance}type");
            if (report == null)
            {
                return null;
            }

            return "SitRep-"+reportTypeAttribute.Value+".xslt";

        }



        /// <summary>
        /// I Parses a URL to find the DE message that it is attempting to look up. 
        /// </summary>
        /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
        /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
        [WebGet(UriTemplate = "DashboardHTML/{ContentKeyStr}?type={sitrepType}&release={release}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
        public Stream GetDashboardHTML(string contentKeyStr, string sitrepType, string release)
        {
            string xsltLocation = "XSLT\\DashboardXSLT\\" + release + "\\";
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
            int hash;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();


            try
            {
                hash = Int32.Parse(contentKeyStr);
            }
            catch (System.FormatException)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>Expected a 32 bit signed integer at the end of the url. You provided (" + contentKeyStr + "), which is not parsable as an integer.</p>" + this.lorem)) as Stream;
            }

            EDXLDEDal dal = new EDXLDEDal();
            //XElement xe = dal.GetContentObjectByHash(hash);
            Uri current = new Uri(HttpRuntime.AppDomainAppPath);
            //Uri current = new Uri(@"C:\Users\rgustafson\Documents\IC.NET-newDB\IC.NET-unstable\IC.NETSOA\ICNETREST\");
            XElement xe = null;
            try
            {
                xe = XElement.Load(new Uri(current, @".\XSLT\DashboardSamples\" + sitrepType + @"\" + hash + @".xml").ToString());
            }
            catch (System.IO.IOException)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>no sample data for those settings</p>" + this.lorem)) as Stream;
            }

            if (xe == null)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</p>" + this.lorem)) as Stream;
            }
            /*
          else
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p>ready "+xe.NodeType.ToString()+"</p>" + this.lorem)) as Stream;
          }*/



            // Enable to just echo the type string as HTML
            //// return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY>" + type + "  valid:" + xmlTransformers.ContainsKey(type).ToString() + "</BODY></HTML>" + lorem)) as Stream;

            if (xmlDashboardTransformers.ContainsKey(sitrepType))
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
                try
                {
                    // return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY>" + HttpRuntime.AppDomainAppPath + xmlTransformers[type] + "</BODY></HTML>" + lorem)) as Stream;
                    return TransformXMLtoHTML(xe, xsltLocation + "XSLT"+sitrepType);
                }
                catch (System.Exception e)
                {
                    WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
                    return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<p><pre>Failed to convert to html \"" + sitrepType + "\"  : " + e.Message + "   ----    " +
                        e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</pre></p>" + this.lorem)) as Stream;
                }
            }
            else
            {
                // Not able to do transformation to HTML for this message type, fallback to showing the XML
                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
                WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;

                return new MemoryStream(encoding.GetBytes(xe.ToString())) as Stream;
            }
        }

        /// <summary>
        /// Transforms a DE object in XML format into HTML.
        /// </summary>
        /// <param name="xe">The XML object to be transformed.</param>
        /// <param name="type">The type of DE message that is being passed in.</param>
        /// <returns>The stream containing the converted html</returns>
        private static Stream TransformXMLtoHTML(XElement xe, string xsltFile)
        {
            // Create the Stream to place the output.
            System.IO.Stream str = new System.IO.MemoryStream();

            // Use .net XSLT libraries to conver the message XML to nice HTML
            System.Xml.Xsl.XslCompiledTransform xslt = new System.Xml.Xsl.XslCompiledTransform();
            XsltSettings xslt_settings = new XsltSettings();
            xslt_settings.EnableScript = true;
            xslt_settings.EnableDocumentFunction = true;

            XmlResolver resolver = new XmlUrlResolver();
            //resolver.Credentials = CredentialCache.DefaultCredentials;

            xslt.Load(HttpRuntime.AppDomainAppPath + xsltFile, xslt_settings, resolver);

            xslt.Transform(new XPathDocument(xe.CreateReader()), null, str);

            // Remember to Flush the Stream and set the position to 0
            str.Flush();
            str.Position = 0;
            return str as Stream;
        }

        /// <summary>
        /// Transforms a DE object in XML format into HTML.
        /// </summary>
        /// <param name="xe">The XML object to be transformed.</param>
        /// <param name="type">The type of DE message that is being passed in.</param>
        /// <returns>The stream containing the converted html</returns>
        private static Stream TransformDEXMLtoHTML(XElement xe, string xsltFile)
        {
          // Create the Stream to place the output.
          System.IO.Stream str = new System.IO.MemoryStream();

          // Use .net XSLT libraries to conver the message XML to nice HTML
          System.Xml.Xsl.XslCompiledTransform xslt = new System.Xml.Xsl.XslCompiledTransform();
          XsltSettings xslt_settings = new XsltSettings();
          xslt_settings.EnableScript = true;
          xslt_settings.EnableDocumentFunction = true;

          XmlResolver resolver = new XmlUrlResolver();
          //resolver.Credentials = CredentialCache.DefaultCredentials;

          // Create an XsltArgumentList.
          XsltArgumentList xslArg = new XsltArgumentList();

          // Add an object to calculate the new book price.
          XsltFunctions obj = new XsltFunctions();
          xslArg.AddExtensionObject("http://csharp.org", obj);

          xslt.Load(HttpRuntime.AppDomainAppPath + xsltFile, xslt_settings, resolver);

          xslt.Transform(new XPathDocument(xe.CreateReader()), xslArg, str);

          // Remember to Flush the Stream and set the position to 0
          str.Flush();
          str.Position = 0;
          return str as Stream;
        }
    }

    public class XsltFunctions
    {
      public string GetAddressFromLatLon(string lat, string lon)
      {
        // if either is null, then assume we have nothing
        if (lat == null || lon == null)
        {
          lat = "0.0";
          lon = "0.0";
        }

        // this is the default string to send if we don't find a legit address
        string address = string.Format("Lat, Lon: {0}, {1}", lat, lon);

        try
        {
          // build the url to get the address from Google Geocoder
          string url = string.Format("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", lat, lon);

          XmlUrlResolver resolver = new XmlUrlResolver();
          resolver.Credentials = CredentialCache.DefaultCredentials;

          // parse the XML
          XmlDocument doc = new XmlDocument();
          doc.XmlResolver = resolver;
          doc.Load(url);

          // Make sure the status of the response is "OK"
          XmlNode statusNode = doc.SelectSingleNode("//GeocodeResponse/status");
          if (statusNode != null)
          {
            string status = statusNode.InnerText;
            if (string.Compare(status, "ok", true) == 0)
            {
              // Loop through the results
              XmlNodeList resultNodes = doc.SelectNodes("//GeocodeResponse/result");
              foreach (XmlNode resultNode in resultNodes)
              {
                XmlNode typeNode = resultNode.SelectSingleNode("type");
                if (typeNode != null)
                {
                  // If the result type is a street address
                  string type = typeNode.InnerText;
                  if (string.Compare(type, "street_address", true) == 0 || string.Compare(type, "route", true) == 0)
                  {
                    XmlNode addrNode = resultNode.SelectSingleNode("formatted_address");
                    if (addrNode != null)
                    {
                      // use the address given
                      address = addrNode.InnerText;
                      break;
                    }
                  }
                }
              }
            }
          }
        }
        catch (Exception)
        {
          // do nothing 
        }
        return address;
      }
    }
}
